package com.empire.module.member.service.mappolygon;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.empire.module.member.dal.dataobject.mappolygonpoint.MapPolygonPointDO;
import com.empire.module.member.dal.mysql.mappolygonpoint.MapPolygonPointMapper;
import lombok.Data;
import org.locationtech.jts.geom.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import com.empire.module.member.controller.admin.mappolygon.vo.*;
import com.empire.module.member.dal.dataobject.mappolygon.MapPolygonDO;
import com.empire.framework.common.pojo.PageResult;
import com.empire.framework.common.util.object.BeanUtils;

import com.empire.module.member.dal.mysql.mappolygon.MapPolygonMapper;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import static com.empire.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.empire.module.member.enums.ErrorCodeConstants.*;

/**
 * 地图多边形信息 Service 实现类
 *
 * @author 主席大人
 */
@Service
@Validated
public class MapPolygonServiceImpl implements MapPolygonService {

    @Resource
    private MapPolygonMapper mapPolygonMapper;

    @Resource
    private MapPolygonPointMapper mapPolygonPointMapper;

    // JTS几何工厂（用于面积计算）
    private final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);

    // 根据配置ID查询多边形（含顶点）
    @Override
    public List<MapPolygonWithPointsVO> getPolygonsByConfigId(String configId) {
        // 1. 查询多边形列表
        LambdaQueryWrapper<MapPolygonDO> polygonQuery = new LambdaQueryWrapper<>();
        polygonQuery.eq(MapPolygonDO::getConfigId, configId);
        List<MapPolygonDO> polygonDOs = mapPolygonMapper.selectList(polygonQuery);
        if (polygonDOs.isEmpty()) {
            return Collections.emptyList(); // 直接返回空列表，避免执行查询
        }
        // 2. 查询所有顶点
        LambdaQueryWrapper<MapPolygonPointDO> pointQuery = new LambdaQueryWrapper<>();
        pointQuery.in(MapPolygonPointDO::getPolygonId, polygonDOs.stream().map(MapPolygonDO::getId).collect(Collectors.toList()));
        pointQuery.orderByAsc(MapPolygonPointDO::getPolygonId, MapPolygonPointDO::getRingIndex, MapPolygonPointDO::getPointIndex);
        List<MapPolygonPointDO> pointDOs = mapPolygonPointMapper.selectList(pointQuery);

        // 3. 组装多边形+顶点
        return polygonDOs.stream().map(polygonDO -> {
            MapPolygonWithPointsVO respVO = BeanUtils.toBean(polygonDO, MapPolygonWithPointsVO.class);
            List<MapPolygonPointVO> points = pointDOs.stream()
                    .filter(pointDO -> pointDO.getPolygonId().equals(polygonDO.getId()))
                    .map(pointDO -> {
                        MapPolygonPointVO pointVO = new MapPolygonPointVO();
                        pointVO.setId(pointDO.getId());
                        pointVO.setRingIndex(pointDO.getRingIndex());
                        pointVO.setLng(pointDO.getLng());
                        pointVO.setLat(pointDO.getLat());
                        pointVO.setPointIndex(pointDO.getPointIndex());
                        return pointVO;
                    }).collect(Collectors.toList());
            respVO.setPoints(points);
            return respVO;
        }).collect(Collectors.toList());
    }

    // 计算多边形面积（平方米）
    private BigDecimal calculatePolygonArea(List<MapPolygonPointVO> points) {
        // 过滤外环顶点（ringIndex=0）
        List<MapPolygonPointVO> outerPoints = points.stream()
                .filter(point -> point.getRingIndex() == 0)
                .sorted(Comparator.comparingInt(MapPolygonPointVO::getPointIndex))
                .toList();

        if (outerPoints.size() < 3) {
            return BigDecimal.ZERO;
        }

        // 构建JTS多边形
        Coordinate[] coordinates = outerPoints.stream()
                .map(point -> new Coordinate(point.getLng(), point.getLat()))
                .toArray(Coordinate[]::new);

        // 闭合多边形（首尾点相同）
        if (!coordinates[0].equals2D(coordinates[coordinates.length - 1])) {
            Coordinate[] closedCoords = new Coordinate[coordinates.length + 1];
            System.arraycopy(coordinates, 0, closedCoords, 0, coordinates.length);
            closedCoords[coordinates.length] = coordinates[0];
            coordinates = closedCoords;
        }

        LinearRing linearRing = geometryFactory.createLinearRing(coordinates);
        Polygon polygon = geometryFactory.createPolygon(linearRing);

        // 转换为平方米（JTS默认单位是度，需投影转换）
        double areaM2 = polygon.getArea() * 1113199906.186217; // 度转平方米系数
        return BigDecimal.valueOf(areaM2).setScale(6, BigDecimal.ROUND_HALF_UP);
    }

    @Transactional
    public void deleteMapPolygon(String id) {
        // 删除顶点（外键级联也可，显式删除更清晰）
        mapPolygonPointMapper.deleteByPolygonId(id);
        // 删除多边形
        mapPolygonMapper.deleteById(id);
    }

    @Override
    @Transactional
    public String createMapPolygon(MapPolygonSaveReqVO createReqVO) {
        // 1、转换数据
        MapPolygonDO mapPolygon = BeanUtils.toBean(createReqVO, MapPolygonDO.class);
        // 2. 计算面积和顶点数量
        BigDecimal area = calculatePolygonArea(createReqVO.getPoints());
        int pointCount = createReqVO.getPoints().size();
        mapPolygon.setPointCount(pointCount);
        mapPolygon.setArea(area);
        mapPolygonMapper.insert(mapPolygon);

        // 3. 保存顶点
        String polygonPoint = mapPolygon.getId();
        List<MapPolygonPointDO> pointDOs = createReqVO.getPoints().stream().map(pointVO -> {
            MapPolygonPointDO pointDO = new MapPolygonPointDO();
            pointDO.setPolygonId(polygonPoint);
            pointDO.setRingIndex(pointVO.getRingIndex());
            pointDO.setLng(pointVO.getLng());
            pointDO.setLat(pointVO.getLat());
            pointDO.setPointIndex(pointVO.getPointIndex());
            return pointDO;
        }).toList();

        pointDOs.forEach(mapPolygonPointMapper::insert);

        // 返回
        return polygonPoint;
    }

    @Override
    @Transactional
    public void updateMapPolygon(MapPolygonSaveReqVO reqVO) {
        // 1. 验证多边形存在
        MapPolygonDO polygonDO = mapPolygonMapper.selectById(reqVO.getId());
        if (polygonDO == null) {
            throw new IllegalArgumentException("多边形不存在：" + reqVO.getId());
        }

        // 2. 计算面积和顶点数量
        BigDecimal area = calculatePolygonArea(reqVO.getPoints());
        int pointCount = reqVO.getPoints().size();

        // 3. 更新多边形基础信息
        polygonDO.setName(reqVO.getName());
        polygonDO.setStrokeColor(reqVO.getStrokeColor());
        polygonDO.setStrokeWeight(reqVO.getStrokeWeight());
        polygonDO.setFillColor(reqVO.getFillColor());
        polygonDO.setFillOpacity(reqVO.getFillOpacity());
        polygonDO.setRoomLevel(reqVO.getRoomLevel());
        polygonDO.setSortOrder(reqVO.getSortOrder());
        polygonDO.setArea(area);
        polygonDO.setPointCount(pointCount);

        mapPolygonMapper.updateById(polygonDO);

        // 4. 删除旧顶点，保存新顶点
        mapPolygonPointMapper.deleteByPolygonId(reqVO.getId());
        List<MapPolygonPointDO> pointDOs = reqVO.getPoints().stream().map(pointVO -> {
            MapPolygonPointDO pointDO = new MapPolygonPointDO();
            pointDO.setPolygonId(reqVO.getId());
            pointDO.setRingIndex(pointVO.getRingIndex());
            pointDO.setLng(pointVO.getLng());
            pointDO.setLat(pointVO.getLat());
            pointDO.setPointIndex(pointVO.getPointIndex());
            return pointDO;
        }).toList();

        pointDOs.forEach(mapPolygonPointMapper::insert);

    }

    @Override
    public MapPolygonDO getMapPolygon(String id) {
        return mapPolygonMapper.selectById(id);
    }

    @Override
    public PageResult<MapPolygonDO> getMapPolygonPage(MapPolygonPageReqVO pageReqVO) {
        return mapPolygonMapper.selectPage(pageReqVO);
    }

}

